package ThreadSafety;

class Count {
    public int count;
    synchronized public void add() {
        //代码块中加锁
        synchronized (this) {
            count++;
        }
    }
    public void add2() {
        count++;
    }
}
public class Safe {
    public static void main(String[] args) throws InterruptedException {
        Count count = new Count();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                //给add方法加锁(比并发执行慢,但还是比全部串行块),让这部分串行执行,其余for循环这里的比较和自增操作,都是不必加锁的,可以并发执行的
                //t1执行add的时候,就加上锁了,针对count这个对象加上了锁
                count.add();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                //t2执行add的时候,也尝试对count加锁,但是由于count已经被t1被占用了,因此这里的加锁操作就会被阻塞
                //线程阻塞,不代表count这个对象不能使用
                count.add();

                //这个操作就是一个线程加锁,一个线程不加锁,就不会出现锁竞争,此时的结果就会出现"抢占式执行"
                //count.add2();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        //这个现象就是典型的线程安全问题,预期的结果和实际结果不不一样
        /**
         * 结果一般会在[50000-100000],但是也可能出现小于50000的情况
         * 比如t2线程自增了2次,但是t1第一次读取到内存中的数据是0,等t2自增两次并且将数据存入到内存,此时t1在自增,并将数据存入内存中的数据是1
         * 即运行3次,结果只是1,那么结果就会出现count小于50000*/
        System.out.println("count = " + count.count);
    }
}